﻿
namespace EnforcerExample.P4NPlugins
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Mono.Cecil;
    using Patterns4Net.Core.CecilExtensions;
    using Patterns4Net.Attributes;
    using Patterns4Net.PatternEnforcer.Core.Patterns;

    public class BaseCaller : Attribute, IPattern, IPatternAttribute, IPatternCheckerProvider
    {
        public BaseCaller()
        {
        }

        public BaseCaller(IDictionary<string, object> values)
        {
            this.TargetType = ((TypeReference)values["-Target"]).SafeResolve();
            this.TargetBase = this.TargetType.BaseType.SafeResolve();
        }

        public string Name
        {
            get { return "Base Caller"; }
        }

        private TypeDefinition TargetType { get; set; }

        private TypeDefinition TargetBase { get; set; }

        //// This is used by Architecture Explorer, we don't need it now
        public AbstractionLevel? AbstractionLevel
        {
            get { return null; }
        }

        public IPatternChecker GetChecker()
        {
            return new Checker();
        }

        private class Checker : FluentPatternChecker<BaseCaller>
        {
            public Checker()
            {
                this.Type(pattern => pattern.TargetType)
                    .Methods(method => method.OverridesBaseMethod())
                    .Check((pattern, method) =>
						   method.GetMethodCalls() != null &&
                           method.GetMethodCalls().Any(call =>
													   call.HasTargetObject &&
                                                       call.TargetObject.IsThisParameter &&
                                                       call.Method.DeclaringType.IsEqual(pattern.TargetBase) &&
                                                       call.Method.Name == method.Name),
                           (pattern, method) =>
                           string.Format(
                               "The class {0} does not call base method in overridden method {1}",
                               pattern.TargetType.Name,
                               method.Name));
            }
        }
    }
}
